//
//  OrientationImageDecoder.m
//  YuanXinCamera
//
//  Created by GJS on 2018/5/28.
//  Copyright © 2018年 晏德智. All rights reserved.
//

#import "OrientationImageDecoder.h"

#import <ImageIO/ImageIO.h>
#import <QuartzCore/QuartzCore.h>

#import <React/RCTImageUtils.h>
#if __has_include(<React/RCTBridgeModule.h>)
#import <React/RCTUtils.h>
#else
#import <React/RCTUtils.h>
#endif

@implementation OrientationImageDecoder

RCT_EXPORT_MODULE()

- (BOOL)canDecodeImageData:(NSData *)imageData
{
    char header[7] = {};
    [imageData getBytes:header length:6];
    
    // 不处理GIF
    return !(!strcmp(header, "GIF87a") || !strcmp(header, "GIF89a"));
}

- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
                                              size:(CGSize)size
                                             scale:(CGFloat)scale
                                        resizeMode:(RCTResizeMode)resizeMode
                                 completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
    // UIImage *image = [UIImage imageWithData:imageData];
    
    // Decompress the image data (this may be CPU and memory intensive)
    // UIImage *image = RCTDecodeImageWithData(imageData, size, scale, resizeMode);
    UIImage *image = OrientationDecodeImageWithData(imageData, size, scale, resizeMode);
    
    
#if RCT_DEV
    CGSize imagePixelSize = RCTSizeInPixels(image.size, image.scale);
    CGSize screenPixelSize = RCTSizeInPixels(RCTScreenSize(), RCTScreenScale());
    if (imagePixelSize.width * imagePixelSize.height >
        screenPixelSize.width * screenPixelSize.height) {
        RCTLogInfo(@"[PERF ASSETS] Loading image at size %@, which is larger "
                   "than the screen size %@", NSStringFromCGSize(imagePixelSize),
                   NSStringFromCGSize(screenPixelSize));
    }
#endif
    
    if (image) {
        completionHandler(nil, image);
    } else {
        NSString *errorMessage = [NSString stringWithFormat:@"Error decoding image data <NSData %p; %tu bytes>", imageData, imageData.length];
        NSError *finalError = RCTErrorWithMessage(errorMessage);
        completionHandler(finalError, nil);
    }
    
    return ^{};
}

UIImage *__nullable OrientationDecodeImageWithData(NSData *data,
                                           CGSize destSize,
                                           CGFloat destScale,
                                           RCTResizeMode resizeMode)
{
    CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    if (!sourceRef) {
        return nil;
    }
    
    // Get original image size
    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, NULL);
    if (!imageProperties) {
        CFRelease(sourceRef);
        return nil;
    }
    
    NSNumber *imageOrientation = CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation);
    NSInteger exifOrientation = imageOrientationFromEXIFOrientation([imageOrientation integerValue]);
    
    CFRelease(imageProperties);
    
    if (exifOrientation == UIImageOrientationUp) {
        return RCTDecodeImageWithData(data, destSize, destScale, resizeMode);
    } else {
        return [UIImage imageWithData:data];
    }
}

UIImageOrientation imageOrientationFromEXIFOrientation(NSInteger exifOrientation)
{
    // CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility
    UIImageOrientation imageOrientation = UIImageOrientationUp;
    switch (exifOrientation) {
        case 1:
            imageOrientation = UIImageOrientationUp;
            break;
        case 3:
            imageOrientation = UIImageOrientationDown;
            break;
        case 8:
            imageOrientation = UIImageOrientationLeft;
            break;
        case 6:
            imageOrientation = UIImageOrientationRight;
            break;
        case 2:
            imageOrientation = UIImageOrientationUpMirrored;
            break;
        case 4:
            imageOrientation = UIImageOrientationDownMirrored;
            break;
        case 5:
            imageOrientation = UIImageOrientationLeftMirrored;
            break;
        case 7:
            imageOrientation = UIImageOrientationRightMirrored;
            break;
        default:
            break;
    }
    return imageOrientation;
}

// Convert an EXIF image orientation to an iOS one.
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation {
    // CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility
    UIImageOrientation imageOrientation = UIImageOrientationUp;
    switch (exifOrientation) {
        case 1:
            imageOrientation = UIImageOrientationUp;
            break;
        case 3:
            imageOrientation = UIImageOrientationDown;
            break;
        case 8:
            imageOrientation = UIImageOrientationLeft;
            break;
        case 6:
            imageOrientation = UIImageOrientationRight;
            break;
        case 2:
            imageOrientation = UIImageOrientationUpMirrored;
            break;
        case 4:
            imageOrientation = UIImageOrientationDownMirrored;
            break;
        case 5:
            imageOrientation = UIImageOrientationLeftMirrored;
            break;
        case 7:
            imageOrientation = UIImageOrientationRightMirrored;
            break;
        default:
            break;
    }
    return imageOrientation;
}

@end
